﻿namespace ContactsSync.Providers.LinkedIn
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Xml.Linq;
    using DotNetOpenAuth.ApplicationBlock;
    using DotNetOpenAuth.OAuth;
    using DotNetOpenAuth.Samples.OAuthConsumerWpf;
    using Infrastructure;
    using Infrastructure.Models;
    using Microsoft.Practices.Composite.Events;

    public class LinkedInContactsProvider : IContactsProvider
    {
        private const string ConsumerKey = "TXl5-yWX2gBHjEo3HexR9rhnSoh9YgPUIXOMwN80KR8N9P6uEKy-A4bQzTV-AWZA";
        private const string ConsumerSecret = "sKURVz2elkO_dBwx8COl7nV8_f_FuW12yI_wNx2y_BxtGtC8CMSj0bCCUxvE4D7C";

        private readonly InMemoryTokenManager tokenManager;
        private DesktopConsumer consumer;

        public LinkedInContactsProvider()
        {
            this.tokenManager = new InMemoryTokenManager();

            if (!string.IsNullOrEmpty(ConsumerKey))
            {
               this.tokenManager.ConsumerKey = ConsumerKey;
               this.tokenManager.ConsumerSecret = ConsumerSecret;
            }
        }

        public event EventHandler<DataEventArgs<IList<Contact>>> RetrieveContactsCompleted;

        public string ProviderName
        {
            get { return "LinkedIn"; }
        }

        public void RetrieveContactsAsync()
        {
            string linkedInAccessToken = string.Empty;

            try
            {
                this.consumer = new DesktopConsumer(LinkedInConsumer.ServiceDescription, this.tokenManager);

                Authorize.FetchUri callback = (DesktopConsumer desktopConsumer, out string requestToken) => desktopConsumer.RequestUserAuthorization(null, null, out requestToken);

                Authorize auth = new Authorize(this.consumer, callback);

                bool? result = auth.ShowDialog();

                if (result.HasValue && result.Value)
                {
                    linkedInAccessToken = auth.AccessToken;
                }

                BackgroundWorker backgroundWorker = new BackgroundWorker();
                backgroundWorker.RunWorkerCompleted += this.BackgroundWorker_RunWorkerCompleted;
                backgroundWorker.DoWork += this.BackgroundWorker_DoWork;
                backgroundWorker.RunWorkerAsync(linkedInAccessToken);
            }
            catch
            {
                this.OnRetrieveContactsCompleted(new List<Contact>());
            }
        }

        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            IList<Contact> contacts = new List<Contact>();

            string linkedInAccessToken = e.Argument as string;

            if (linkedInAccessToken != string.Empty)
            {
                XDocument connections = LinkedInConsumer.GetConnections(this.consumer, linkedInAccessToken);

                contacts = connections.Descendants("person").Select(contact =>
                            new Contact
                            {
                                Id = contact.Element("id").GetValue(),
                                FirstName = contact.Element("first-name").GetValue(),
                                LastName = contact.Element("last-name").GetValue(),
                                ImageSource = contact.Element("picture-url").GetValue()
                            }).ToList();
            }

            e.Result = contacts;
        }

        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            IList<Contact> contacts = e.Result as IList<Contact>;

            if (contacts == null)
            {
                contacts = new List<Contact>();
            }

            this.OnRetrieveContactsCompleted(contacts);
        }

        private void OnRetrieveContactsCompleted(IList<Contact> contacts)
        {
            EventHandler<DataEventArgs<IList<Contact>>> completed = this.RetrieveContactsCompleted;
            if (completed != null)
            {
                completed(this, new DataEventArgs<IList<Contact>>(contacts));
            }
        }
    }
}